<template>
  <el-form :model="form" ref="formRef">
      <el-table
        :data="tableData"
        ref="multipleTable"
        border
        row-key="id"
        :row-class-name="getRowClassName"
        :header-row-class-name="getHeaderRowClassName"
        size="mini"
        max-height="500px"
        style="width: 100%"
        @select="selectFun"
        @select-all="selectAllFun"
        @selection-change="selectionChangeFun"
        :header-cell-style="{ background: '#fafafa' }"
    >
        <el-table-column type="selection" width="55"> </el-table-column>
        <el-table-column prop="date" label="日期" sortable width="180">
        </el-table-column>
        <el-table-column prop="name" label="姓名" sortable width="180">
        </el-table-column>
        <el-table-column prop="address" label="地址"> </el-table-column>
        </el-table>
  </el-form>
</template>
<script>
export default {
  name: 'listSelectDemo',
  data () {
    return {
      // 表格数据
      tableData: [
        {
          id: 1,
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 2,
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1519 弄',
          children: [
            {
              id: 3,
              date: '2016-05-01',
              name: '王小虎',
              address: '上海市普陀区金沙江路 1519 弄',
              children: [
                {
                  id: 4,
                  date: '2016-05-01',
                  name: '王小虎',
                  address: '上海市普陀区金沙江路 1519 弄'
                },
                {
                  id: 5,
                  date: '2016-05-01',
                  name: '王小虎',
                  address: '上海市普陀区金沙江路 1519 弄'
                }
              ]
            },
            {
              id: 6,
              date: '2016-05-01',
              name: '王小虎',
              address: '上海市普陀区金沙江路 1519 弄'
            }
          ]
        }
      ],
      // 勾选中的行数据
      selectedData: []
    }
  },
  mounted () {
    this.initData(this.tableData)
  },
  methods: {
    // 初始化数据
    initData (data, parentId) {
      data && data.length && data.forEach((item) => {
        // isSelect状态：true为选中状态，false为未选中状态 ，空字符串为未知状态
        item.isSelect = false // 默认为不选中
        parentId && (item.parentId = parentId)
        if (item.children && item.children.length) {
          this.initData(item.children, item.id)
        }
      })
    },
    // 监听选中事件
    selectionChangeFun (selection) {
      this.selectedData = selection
    },
    // 复选框点击事件
    selectFun (selection, row) {
      this.setRowIsSelect(row)
    },
    // 复选框点击事件
    setRowIsSelect (row) {
      // 为空字符串则对应行半选态，点击则应该变为全选，则为true
      if (row.isSelect === '') {
        this.$refs.multipleTable.toggleRowSelection(row, true)
      }
      row.isSelect = !row.isSelect
      const _this = this
      // 判断操作的是子级点复选框还是父级点复选框，如果是父级点，则控制子级点的全选和不全选

      // 1、只是父级 2、既是子集，又是父级 3、只是子级
      const levelStatus = getCurrentLevel(row)

      if (levelStatus === 1) {
        // 操作的是父级，则所有子集同步父级状态
        selectAllChildren(row.children)
      } else if (levelStatus === 2) {
        selectAllChildren(row.children)
        operateLastLevel(row)
      } else if (levelStatus === 3) {
        operateLastLevel(row)
      }
      // 判断当前操作行的层级状态
      function getCurrentLevel (row) {
        // 1、只是父级 2、既是子集，又是父级 3、只是子级
        if (row.parentId === undefined) {
          return 1
        } else if (row.parentId && !(row.children && row.children.length)) {
          return 3
        } else {
          return 2
        }
      }

      // 递归处理children子级数据的isSelect状态以及对选框状态
      function selectAllChildren (children) {
        children && children.length && children.forEach((item) => {
          item.isSelect = row.isSelect
          _this.toggleRowSelection(item, row.isSelect)
          if (item.children && item.children.length) {
            selectAllChildren(item.children)
          }
        })
      }
      // 子级向上操作父级状态
      function operateLastLevel (row) {
        // 操作的是子节点,则
        // 1、获取父节点
        // 2、判断子节点选中个数，如果全部选中则父节点设为选中状态，如果都不选中，则为不选中状态，如果部分选择，则设为不明确状态
        const item = getExplicitNode(_this.tableData, row.parentId)
        const selectStatusArr = getSelectStatus([], item.children)

        // 判断所有子集选中态，都为true则父级也选中，都为false则不选中，否则为半选
        const allSelected = selectStatusArr.every(selectItem => selectItem === true)
        const allUnselected = selectStatusArr.every(selectItem => selectItem === false)
        if (allSelected) {
          item.isSelect = true
          _this.toggleRowSelection(item, true)
        } else if (allUnselected) {
          item.isSelect = false
          _this.toggleRowSelection(item, false)
        } else {
          item.isSelect = ''
        }
        // 如果当前节点的parentId存在，则还有父级，继续递归往上一层操作
        if (item.parentId !== undefined) {
          operateLastLevel(item)
        }
      }
      // 递归获取所有子级的选中状态数组
      function getSelectStatus (selectStatusArr, children) {
        if (!children || !children.length) {
          return selectStatusArr
        }
        children.forEach((child) => {
          selectStatusArr.push(child.isSelect)
          if (child.children && child.children.length) {
            getSelectStatus(selectStatusArr, child.children)
          }
        })
        return selectStatusArr
      }

      // 获取明确父级的节点
      function getExplicitNode (tableData, parentId) {
        let result = null
        function findNode (data) {
          for (let i = 0; i < data.length; i++) {
            if (data[i].id === parentId) {
              result = data[i]
              break
            }
            if (data[i].children && data[i].children.length) {
              findNode(data[i].children)
            }
          }
        }
        findNode(tableData)
        return result
      }
    },
    // 表格全选事件
    selectAllFun (selection) {
      const firstLevelStatus = this.tableData.map(item => item.isSelect)
      // 判断一级是否是全选.如果一级产品全为true，则设置为取消全选，否则全选
      const isAllSelect = firstLevelStatus.every(status => status)
      // 设置所以一级和二级为选中状态
      this.tableData.forEach((item) => {
        item.isSelect = isAllSelect
        this.toggleRowSelection(item, !isAllSelect)
        this.selectFun(selection, item)
      })
    },
    // 设置当前行的选中态
    toggleRowSelection (row, flag) {
      if (row) {
        this.$nextTick(() => {
          this.$refs.multipleTable &&
          this.$refs.multipleTable.toggleRowSelection(row, flag)
        })
      }
    },
    // 表格行样式 当当前行的状态为不明确状态时，添加样式，使其复选框为不明确状态样式
    getRowClassName ({ row }) {
      if (row.isSelect === '') {
        return 'indeterminate'
      }
    },
    // 表格标题样式 当一级目录有为不明确状态时，添加样式，使其全选复选框为不明确状态样式
    getHeaderRowClassName ({ row }) {
      const isIndeterminate = this.tableData.some(item => item.isSelect === '')
      if (isIndeterminate) {
        return 'indeterminate'
      }
      return ''
    }
  }
}
</script>

<style  scoped>
.indeterminate .el-checkbox__input .el-checkbox__inner {
  background-color: #409eff !important;
  border-color: #409eff !important;
  color: #fff !important;
}

.indeterminate .el-checkbox__input.is-checked .el-checkbox__inner::after {
  transform: scale(0.5);
}

.indeterminate .el-checkbox__input .el-checkbox__inner {
  background-color: #f2f6fc;
  border-color: #dcdfe6;
}

.indeterminate .el-checkbox__input .el-checkbox__inner::after {
  border-color: #c0c4cc !important;
  background-color: #c0c4cc;
}

.indeterminate .el-checkbox__input .el-checkbox__inner::after {
  content: '';
  position: absolute;
  display: block;
  background-color: #fff;
  height: 2px;
  transform: scale(0.5);
  left: 0;
  right: 0;
  top: 5px;
  width: auto !important;
}
</style>
